package com.hmsm.sys.bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class RTXDeptBean<D extends LocalDept<D, U>, U extends LocalUser> {

	private static Log log = LogFactory.getLog(RTXDeptBean.class);
	
	private static int nextId = -1;

	private Map<Integer, RTXDeptBean<D, U>> deptMap;
	
	private Map<Long, RTXDeptBean<D, U>> relevanceDeptMap;
	
	public Map<Long, RTXDeptBean<D, U>> getRelevanceDeptMap() {
		return relevanceDeptMap;
	}

	public void setRelevanceDeptMap(Map<Long, RTXDeptBean<D, U>> relevanceDeptMap) {
		this.relevanceDeptMap = relevanceDeptMap;
	}

	private Map<Integer, RTXDeptBean<D, U>> locaDeptMap;

	public void setDeptMap(Map<Integer, RTXDeptBean<D, U>> deptMap) {
		this.deptMap = deptMap;
	}

	private Map<Integer, RTXUserBean> userMap;

	public Map<Integer, RTXUserBean> getUserMap() {
		return userMap;
	}

	public void setUserMap(Map<Integer, RTXUserBean> userMap) {
		this.userMap = userMap;
	}
	
	private Map<Serializable, RTXUserBean> relevanceUserMap;

	public Map<Serializable, RTXUserBean> getRelevanceUserMap() {
		return relevanceUserMap;
	}

	public void setRelevanceUserMap(Map<Serializable, RTXUserBean> relevanceUserMap) {
		this.relevanceUserMap = relevanceUserMap;
	}

	private Integer id;
	private Integer parentId;

	private Long relevanceId;
	private String deptName;
	private int sortId;
	private RTXDeptBean<D, U> parent;
	private List<RTXDeptBean<D, U>> subDepts;
	private List<RTXDeptBean<D, U>> moveOutDepts;
	private List<RTXUserBean> users;
	private D bindDept; // 绑定的本地部门

	public RTXDeptBean(){
		this.id = nextId++;
	}
	
	public RTXDeptBean(D localDept) {
		this.bindDept = localDept;
		if (nextId==0){
			deptMap = new HashMap<Integer, RTXDeptBean<D, U>>();
			locaDeptMap = new HashMap<Integer, RTXDeptBean<D, U>>();
			userMap = new HashMap<Integer, RTXUserBean>();
		}
		if (localDept!=null){
			this.id = nextId++;
			this.deptName = localDept.getName();
		}
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public D getBindDept() {
		return bindDept;
	}

	public List<RTXUserBean> getUsers() {
		return users;
	}

	public void setUsers(List<RTXUserBean> users) {
		this.users = users;
	}

	public RTXDeptBean<D, U> getParent() {
		return parent;
	}

	public void setParent(RTXDeptBean<D, U> parent) {
		this.parent = parent;
	}

	public List<RTXDeptBean<D, U>> getSubDepts() {
		return subDepts;
	}

	public void setSubDepts(List<RTXDeptBean<D, U>> subDepts) {
		this.subDepts = subDepts;
	}

	public List<RTXDeptBean<D, U>> getMoveOutDepts() {
		return moveOutDepts;
	}

	public void setMoveOutDepts(List<RTXDeptBean<D, U>> moveOutDepts) {
		this.moveOutDepts = moveOutDepts;
	}

	public Long getRelevanceId() {
		return relevanceId;
	}

	public void setRelevanceId(Long relevanceId) {
		this.relevanceId = relevanceId;
	}

	public Integer getParentId() {
		return parentId;
	}

	public void setParentId(Integer parentId) {
		this.parentId = parentId;
	}

	public String getDeptName() {
		return deptName;
	}

	public void setDeptName(String deptName) {
		this.deptName = deptName;
	}

	public int getSortId() {
		return sortId;
	}

	public void setSortId(int sortId) {
		this.sortId = sortId;
	}

	public List<RTXDeptBean<D, U>> getAllDepts() {
		List<RTXDeptBean<D, U>> allDepts = new ArrayList<RTXDeptBean<D, U>>();

		if (subDepts!=null){
			for (RTXDeptBean<D, U> subDept : subDepts) {
				allDepts.add(subDept);
				List<RTXDeptBean<D, U>> list = subDept.getAllDepts();
				for (RTXDeptBean<D, U> sub1Dept : list) {
					allDepts.add(sub1Dept);
				}
			}
		}

		return allDepts;
	}

	public List<RTXUserBean> getAllUsers() {
		List<RTXUserBean> allUsers = new ArrayList<RTXUserBean>();

		if (users!=null){
			for (RTXUserBean user : users) {
				allUsers.add(user);
			}
		}

		for (RTXDeptBean<D, U> depart : getAllDepts()) {
			if (depart.getSubDepts()!=null){
				for (RTXUserBean user : depart.getUsers()) {
					allUsers.add(user);
				}
			}
		}
		return allUsers;
	}

	public int getLevel() {
		int level;

		if (parent == null) {
			level = 0;
		} else {
			level = parent.getLevel() + 1;
		}

		return level;
	}
	
	private boolean organization = false;

	public boolean isOrganization() {
		return organization;
	}
	
	public void setOrganization(boolean organization){
		this.organization = organization;
	}

	/**
	 * 获取所属组织机构
	 * @return
	 */
	public RTXDeptBean<D, U> getOrg() {
		RTXDeptBean<D, U> rtxOrg = null;

		if (this.organization) {
			rtxOrg = this;
		} else {
			if (parent != null) {
				rtxOrg = parent.getOrg();
			}
		}

		return rtxOrg;
	}
	
	public String toString(){
		return deptName;
	}

	/**
	 * 绑定指定的本地组织机构，并向下逐级比对部门及人员，绑定比对成功的部门及人员
	 * 
	 * @param rtxDept
	 * @param deptInfoPo
	 */
	public void bind(D deptInfoPo) {
		// 关联匹配组织机构
		bindDept = deptInfoPo;
		deptInfoPo.bind(this);
		
		if(relevanceId!=null){
			// 是远程节点，需要对直属人员及下级部门进行匹配操作
			matching();
			log.debug("匹配完成！");
		}else{
			// TODO 下级部门先不管，直属人员呢
		}
	}

	/**
	 * 对绑定后的部门节点的用户及下级部门进行匹配处理
	 */
	private void matching(){
		List<RTXDeptBean<D, U>> rtxDeptList; // 要处理的远程部门列表

		List<RTXDeptBean<D, U>> addDeptList = new ArrayList<RTXDeptBean<D, U>>();// 要添加的部门
		final List<D> removeDeptList = new ArrayList<D>(); // 可能需要删除的本地部门

		List<RTXUserBean> rtxUserList; // 要处理的远程人员列表

		log.info("远 " + this.deptName + "" + (isRelevanceRoot() ? "根" : "") + "-" + bindDept.getName());
		// 逐级处理
		rtxDeptList = getSubDepts();

		for(Object dept:bindDept.getSubDepts()){
			removeDeptList.add((D) dept);			
		}
		
		if (isRelevanceRoot()){
			// 仅在同步根部门进行人员匹配操作，
			rtxUserList = getAllUsers();
		}else{
			// 非根部门不再重复处理
			rtxUserList = new ArrayList<RTXUserBean>();
		}
		
		// 第一轮，优先检按原来已匹配过的idType进行
		for (RTXDeptBean<D, U> rtxSubDept:rtxDeptList){
			D findDeptInfo = null;
			
			findDeptInfo = (D) bindDept.getSubDepartByRelevanceId(rtxSubDept.getRelevanceId());
			if (findDeptInfo == null) {
				findDeptInfo = (D) bindDept.getSubDepartByName(rtxSubDept.getDeptName());
			}
			
			if (findDeptInfo != null){
				// 是否又是一个远程关联的根
				if (!rtxSubDept.isRelevanceRoot()){
					rtxSubDept.bind(findDeptInfo);
				}else{
					
				}
				removeDeptList.remove(findDeptInfo);
			} else {
				addDeptList.add(rtxSubDept);
			}
		}

		// 匹配所有所属用户
		for (RTXUserBean rtxUserBean : rtxUserList) {
			// 匹配
			LocalUser userInfo = bindDept.getUserByRelevanceId(rtxUserBean.getRelevanceId());
			if (userInfo==null){
				userInfo = bindDept.getUser(rtxUserBean.getName(), rtxUserBean.getUserName());
			}
			if (userInfo != null) {
				rtxUserBean.setBindUser(userInfo);
				userInfo.setBindUser(rtxUserBean);
			}
		}

		// 第二轮，匹配失败的部门即为要添加的部门, 从要删除的部门中按名称匹配一遍
		for (RTXDeptBean<D, U> rtxSubDept : addDeptList) {
			
		}
		
		// 第三轮，匹配失败部门，按成员所属部门匹配
		for (RTXDeptBean<D, U> rtxSubDept : addDeptList) {
			D findDeptInfo = null;
			Map<D, Integer> deptCountMap = new HashMap<D, Integer>();
			if (rtxSubDept.getSubDepts()!=null){
				for (RTXDeptBean<D, U> rtxDeptBean : rtxSubDept.getSubDepts()) {
					if (rtxDeptBean.getBindDept() != null && removeDeptList.contains(rtxDeptBean.getBindDept())) {
						findDeptInfo = (D) rtxDeptBean.getBindDept();
						if (deptCountMap.containsKey(findDeptInfo)) {
							int count = deptCountMap.get(findDeptInfo) + 1;
							deptCountMap.put(findDeptInfo, count);
						} else {
							deptCountMap.put(findDeptInfo, 1);
						}
					}
				}
			}
			if (rtxSubDept.getUsers()!=null){
				for (RTXUserBean rtxUserBean2 : rtxSubDept.getUsers()) {
					// 需要添加的部门成员匹配的部门是要删除的部门，应该就是部门改名
					if (rtxUserBean2.getBindUser() != null
							&& removeDeptList.contains(rtxUserBean2.getBindUser().getDepart())) {
						findDeptInfo = (D) rtxUserBean2.getBindUser().getDepart();
						if (deptCountMap.containsKey(findDeptInfo)) {
							int count = deptCountMap.get(findDeptInfo) + 1;
							deptCountMap.put(findDeptInfo, count++);
						} else {
							deptCountMap.put(findDeptInfo, 1);
						}
					}
				}
			}
			int maxCount = 0;
			for (D deptInfo2 : deptCountMap.keySet()) {
				Integer count = deptCountMap.get(deptInfo2);
				if (count > maxCount) {
					findDeptInfo = deptInfo2;
					maxCount = count;
				}
			}
			if (findDeptInfo != null) {
				rtxSubDept.bind(findDeptInfo);
				removeDeptList.remove(findDeptInfo);
			}
		}
	}

	private boolean isRelevanceRoot() {
		boolean isRelevanceRoot = false;
		
		if (bindDept!=null){
			isRelevanceRoot = !bindDept.getRelevanceType().equals(""); 
		}
		
		return isRelevanceRoot;
	}

	public static void cleanId() {
		nextId = 0;
	}

	public boolean isSyncNeed() {
		boolean syncNeed = false;
		
		D deptInfo = (D) this.bindDept;
		
		if (deptInfo!=null&&deptInfo.isSyncNeed()){
			syncNeed = true;
		}
	
//		if (!syncNeed&&parent!=null){
//			syncNeed = parent.isSyncNeed();
//		}
		
		return syncNeed;
	}

	public void putRtxDept(RTXDeptBean<D, U> rtxDept) {
		deptMap.put(rtxDept.getId(), rtxDept);
		if (rtxDept.getBindDept()!=null){
			locaDeptMap.put(rtxDept.getBindDept().getPkId(), rtxDept);
		}
	}

	public void putRelevanceDept(RTXDeptBean<D, U> rtxDept) {
		relevanceDeptMap.put(rtxDept.getRelevanceId(), rtxDept);
	}

	public RTXDeptBean<D, U> getRtxDept(Integer id) {
		return deptMap.get(id);
	}

	public RTXDeptBean<D, U> getSyncRootDept() {
		RTXDeptBean<D, U> syncRootDept = null;
		
		if(isSyncNeed()){
			syncRootDept = this;
		}else if(parent!=null){
			syncRootDept = parent.getSyncRootDept();
		}
		
		return syncRootDept;
	}

}
